#!/usr/bin/env python

# Copyright 2012 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Handler to provide information to RPs about registered attributes."""

import json
import logging
from base import BaseHandler
import common
from lib import authz
from lib import http
from lib.accept_content import accept_content
from lib.loggable import loggable
import model

__author__ = 'Maciej Machulak'
__maintainer__ = 'Maciej Machulak'
__email__ = 'mmachulak@google.com'

__copyright__ = 'Copyright 2012, Google Inc.'
__license__ = 'Apache License 2.0'
__version__ = '0.2'
__status__ = 'Prototype'

_SCOPE_PREFIX = 'https://www.googleapis.com/auth/'
_STREETIDENTITY_SCOPES_READ = [
    'https://www.googleapis.com/auth/streetidentity.read',
    'https://www.googleapis.com/auth/verifiedage.read',
    'https://www.googleapis.com/auth/verifiedgender.read']
_STREETIDENTITY_SCOPES_WRITE = [
    'https://www.googleapis.com/auth/streetidentity.write',
    'https://www.googleapis.com/auth/verifiedage.write',
    'https://www.googleapis.com/auth/verifiedgender.write']
_STREETIDENTITY_SCOPES_ALL = \
_STREETIDENTITY_SCOPES_READ.extend(_STREETIDENTITY_SCOPES_WRITE)

_SCOPES_ALL = ["streetidentity.read",
               "verifiedage.read",
               "verifiedgender.read"]

class Setup(BaseHandler):
  """Temporary setup handler."""

  @loggable('setup handler')
  def get(self, *args):

    user = model.User(user_id = "123456789")
    user.put()

    application = model.Application(client_id = "someclientid", user = user)
    application.put()

    application2 = model.Application(client_id = "otherclientid", user = user)
    application2.put()

    ap = model.AttributeProvider(application = application,
                                 user = user,
                                 scopes = ["streetidentity.read",
                                           "verifiedgender.read"])
    ap.put()

    ap = model.AttributeProvider(application = application2,
                                 user = user,
                                 scopes = _SCOPES_ALL)
    ap.put()


class DiscoveryHandler(BaseHandler):
  """Handler to provide info to RPs about registered attribute providers."""

#  @authz.api_authz_required(scopes=_STREETIDENTITY_SCOPES_ALL)
  @loggable('discovery handler')
  def get(self, *args):

    user = model.User.all().filter('user_id = ', '222').get()

    scope = self.request.get(common.SI_SCOPE)
    logging.debug('requested info about: %s', scope)
    scopes = []
    if len(scope) > 0:
      scopes = scope.split(' ')
    user_ap_map = {}
    if not scopes:
      logging.debug('showing all APs registered for the user')
      scopes = _SCOPES_ALL
    logging.debug('showing attributes with types: %s', scopes)
    for single_scope in scopes:
      logging.debug('retrieving APs for scope %s', single_scope)
      user_ap_list = model.AttributeProvider.all()\
                                        .filter('user = ', user)\
                                        .filter('scopes = ', single_scope)
      logging.debug('retrieved %d scopes', user_ap_list.count())
      ap_client_id_list = []
      for single_ap in user_ap_list:
        ap_client_id_list.append(single_ap.application.client_id)
      user_ap_map[single_scope] = ap_client_id_list

    logging.debug('showing attribute_providers for a user %s ', user.email)

    self.response.headers[http.Header.content_type] = http.ContentType.json
    self.response.out.write(json.dumps(user_ap_map))
    return

class AttributeRegistrationHandler(BaseHandler):
  """Handler for APs to register attributes for the user."""

  @authz.api_authz_required(
    scopes=['https://www.googleapis.com/auth/streetidentity.write'])
  @accept_content('application/x-www-form-urlencoded')
  @loggable('register attribute')
  def post(self, *args):

    user = self.user
    application = self.application

    # Get required data
    id_ = self.request.get('id')
    type_ = self.request.get('type')
    desc = self.request.get('desc')
    uri = self.request.get('uri')
    provider = self.request.get('provider')

    # Get optional data
    icon_url = self.request.get('icon_url', None)

    logging.debug('obtained new attribute information')
    logging.debug('id_ = %s ', id_)
    logging.debug('type = %s ', type_)
    logging.debug('desc = %s ', desc)
    logging.debug('uri = %s ', uri)
    logging.debug('provider = %s ', provider)
    logging.debug('icon_url = %s ', icon_url)

    logging.debug('creating an attribute object')
    attribute = model.Attribute(
      id=id_,
      type=type_,
      desc=desc,
      uri=uri,
      provider=provider,
      icon_url=icon_url,
      user=user,
      application=application)
    attribute.put()
    logging.debug('attribute stored in db')

    # Prepare the response
    response = {'id': id_,
                'type': type_,
                'desc': desc,
                'uri': uri,
                'provider': provider,
                'icom_url': icon_url
    }

    logging.debug('returning response')
    response_str = json.dumps(response)
    logging.debug('response string %s', response_str)

    self.response.set_status(201)
    self.response.headers[
    http.Header.content_type] = 'application/json; charset=utf-8'
    self.response.out.write(response_str)
    return

class AttributeRevocationHandler(BaseHandler):
  """Handler for APs to de-register attributes for the user."""

  @authz.api_authz_required(
    scopes=['https://www.googleapis.com/auth/streetidentity.write'])
  @accept_content('application/x-www-form-urlencoded')
  @loggable('delete attribute')
  def post(self, *args):

    id_ = self.request.get('id')

    logging.debug('retrieving attribute from db with id: %s', id_)
    attribute = self._get_attribute_by_id(id_)
    if attribute is None:
      logging.debug('attribute not found - 404')
      self.response.set_status(404)
      return
    if (attribute.application.client_id != self.application.client_id) or\
       (attribute.user.email != self.user.email):
      logging.debug(
        'attribute found - but associated with a different client or user')

      # Also return 404 instead of 403 to prevent information leaking
      self.response.set_status(404)
      return
    logging.debug('attribute found - deleting')
    attribute.delete()
    logging.debug('attribute deleted from db - returning 204')
    self.response.set_status(204)

  def _get_attribute_by_id(self, id_):
    return model.Attribute.all().filter('id = ', id_).get()
